/*
 * @Author:
 * @Date: 2023-04-14 10:31:42
 * @Description:
 */
const path = require('path');
const fs = require('fs');
const FontminPlugin = require('fontmin-webpack');
const FontPreloadPlugin = require("webpack-font-preload-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');
// HappyPack 多进程打包
// const HappyPack = require('happypack');
// 每次清除之前的打包文件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// 将css单独打包成一个文件的插件，它为每个包含css的js文件都创建一个css文件。它支持css和sourceMaps的按需加载。
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 压缩css
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');

const {NODE_ENV} = process.env;

function getGlyphsFromTranslations() {
  const translations = [
    path.resolve(__dirname, 'src/i18n', 'en.json'), // 英文翻译文件
    path.resolve(__dirname, 'src/i18n', 'zh.json'), // 中文翻译文件
  ];
  const glyphs = new Set();
  translations.forEach((filePath) => {
    const content = JSON.parse(fs.readFileSync(filePath, 'utf8'));
    const extractText = (obj) => {
      Object.values(obj).forEach((value) => {
        if (typeof value === 'string') {
          [...value].forEach((char) => glyphs.add(char)); // 添加字符到集合
        } else if (typeof value === 'object') {
          extractText(value); // 递归处理嵌套对象
        }
      });
    };
    extractText(content);
  });

  // 将 Set 转换为字符串
  return [...glyphs].join('');
}


module.exports = {
  // 模式: 通过选择 development, production 或 none 之中的一个，来设置 mode 参数，你可以启用 webpack 内置在相应环境下的优化。其默认值为 production。
  mode: NODE_ENV,
  // 入口
  // entry: './src/index.tsx', // 单个入口
  // entry: ['./src/file_1.js', './src/file_2.js'], // 多个文件
  entry: {
    main: './src/index'
  },
  // 文件输出
  output: {
    path: path.resolve(__dirname, 'dist'), // // 输出文件夹路径
    filename: 'bundler.[contenthash].js' //// 输出文件名
  },
  // 缓存-提升速率
  cache: {
    type: 'filesystem',
    // allowCollectingMemory: true,
    buildDependencies: {
      config: [__filename]
    }
  },


  // 模块编译
  module: {
    rules: [
      // 文件处理
      {
        test: /\.(jsx|js)?$/,
        exclude: /node_modules/,
        use: [
          'babel-loader',
        ]
      },
      // 样式处理
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: [
          {
            // 对于 production 模式的构建，建议从你的包中提取 CSS，以便以后能够使用 CSS/JS 资源的并行加载。 可以使用 mini-css-extract-plugin 实现，因为它可以创建单独的 css 文件。 对于 development 模式（包括 webpack-dev-server），你可以使用 style-loader，因为他使用多个 <style></style> 将 CSS 插入到 DOM 中，并且运行得会更快。
            loader:  MiniCssExtractPlugin.loader
          },
          {
            loader: 'css-loader',
            options: {
              modules: {
                    // 使用命名加hash形式命名样式文件
                    localIdentName: '[name].[local].[hash:base64:5]',
                    exportGlobals: true, // 确保支持 :global
              }
            }
          }
        ]
      },
      {
        test: /\.less$/,
        exclude: /node_modules/,
        use: [
          {
            loader:  MiniCssExtractPlugin.loader
          },
          // 使用MiniCssExtractPlugin 不在使用file-loader，这边用file-loader + style-loader打包css处理不好
          // {
          //     loader: 'file-loader',
          //     options: {
          //         name: '[name].[contenthash].[ext]', // 使用 [contenthash] 作为占位符
          //         outputPath: 'styles/' // 定义输出文件夹路径
          //     }
          // },
          {
            loader: 'css-loader',
            options: {
              modules: {
                    // 使用命名加hash形式命名样式文件
                    localIdentName: '[local].[hash:base64:5]',
                    exportGlobals: true, // 确保支持 :global
              }
            }
          },
          {
            loader: 'less-loader',
            options: {
              // lessOptions: {
              //     // 这里可以配置 Less 的其他选项
              // }
            }
          }
        ]
      },
      // 图片处理
      {
        test: /\.(png|jpg|jpeg|gif|svg)$/i, // 使用 file-loader 处理图片文件
        type: 'asset', // webpack 5 内置了打包静态文件的方法， 使用url-loader会有问题，浏览器中图片的引用路径会有问题
        parser: {
          dataUrlCondition: {
            maxSize: 10 * 1024
          }
        },
        generator: {
          filename: 'images/[name].[hash:8][ext]'
        },
        use: [
        ]
      },
    ]
  },
  resolve: {
    extensions: ['.js', '.jsx'], // 支持的文件扩展名
    alias: {
      '@': path.resolve(__dirname, 'src'), // 设置 '@' 别名为项目的 src 目录
      '@components': path.resolve(__dirname, 'src/pages/components'),
      '@assets': path.resolve(__dirname, 'src/assets'),
      "@tools": path.resolve(__dirname, 'src/tools')
    }
  },
  // 热更新
  devServer: {
    static: path.join(__dirname, 'dist'), // 设置静态文件目录
    // 启用 gzip compression：
    compress: true,
    port: 3000,
    hot: false, // 启用热更新 ,每次更新会生成js 和update json文件
    devMiddleware: {
      writeToDisk: true // 将构建的文件写入磁盘
    },
    allowedHosts: 'all'
  },
  optimization: {
    minimize: true,
    removeEmptyChunks: true,
    minimizer: [
      // css压缩
      new CssMinimizerPlugin({
        parallel: true
      }),
      '...'
    ]
  },
  // 插件
  plugins: [
   

    new FontminPlugin({
      glyphs: getGlyphsFromTranslations(), // 保留中文、英文和数字字符
      subset: true,                         // 启用字体子集化
      compress: true,                       // 启用字体压缩
      log: true,       
    }),

     new FontPreloadPlugin({
      loadType: "preload",
      crossorigin: true,
      extensions: ["woff", "ttf", "eot"],
      index: "index.html",
      insertBefore: "head > link:nth-child(1)",
      replaceCallback: ({ indexSource, linksAsString }) => {
        let new_str = linksAsString.replace("auto", "");
        return indexSource.replace("<head>", `<head>
          ${new_str}`);
      },

    }),
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash].css' // CSS 文件名包含了 hash 值
    }),
    // html插件
    new HtmlWebpackPlugin({
      template: './public/index.html',
      filename: 'index.html'
    })
  ]
};
